
__author__ = "unlotto ... at ... gmail ... com"

#VARHOLDER is just a  "char[] pointer to python string cython precaution"#
VARHOLDER = ""

MINDELAY = 0.05 #minimum delay for while loops that try to give commands to the cam

import time

cdef extern from "linux/videodev2.h":
  #from videodev2 we need a few structures and a few definitions#

  #
  cdef int VIDIOC_S_EXT_CTRLS
  cdef struct v4l2_ext_control:
    #an id/value structure that works with pan and tilt#
    unsigned int id
    unsigned int reserved2[2]
    
    #this is a union in the c code with 64bit and 32bit signed int aswell as a reserved soemthing something#
    signed int value
    
  cdef struct v4l2_ext_controls:
    #the final struct for use with ioctl.
    v4l2_ext_control *controls
    unsigned int count
    unsigned int ctrl_class
    unsigned int error_idx
    unsigned int reserved[2]

  #registers as defined in videodev2.h for v4l2 external controls pan and tilt#
  unsigned int V4L2_CID_PAN_RELATIVE
  unsigned int V4L2_CID_TILT_RELATIVE
  unsigned int V4L2_CID_TILT_RESET
  unsigned int V4L2_CID_PAN_RESET
  
  # register other videodev2.h cids
  unsigned int V4L2_CID_PAN_ABSOLUTE
  unsigned int V4L2_CID_TILT_ABSOLUTE
  
  # FOCUS
  unsigned int V4L2_CID_FOCUS_ABSOLUTE
  # unsigned int V4L2_CID_FOCUS_RELATIVE
  # unsigned int V4L2_CID_FOCUS_AUTO
  
  # ZOOM
  # unsigned int V4L2_CID_ZOOM_ABSOLUTE
  # unsigned int V4L2_CID_ZOOM_RELATIVE
  # unsigned int V4L2_CID_ZOOM_AUTO
  
  # unsigned int V4L2_CID_LED1_MODE
  # unsigned int V4L2_CID_LED1_FREQUENCY
  # unsigned int V4L2_CID_DISABLE_PROCESSING
  # unsigned int V4L2_CID_RAW_BITS_PER_PIXEL
  
  # logitech specific
  unsigned int V4L2_CID_LED1_MODE_LOGITECH
  
  # register color-based controls?
  # unsigned int V4L2_CID_HUE

# check line 1223 v4l2_controls.c in guvcview project
# /usr/include/linux/ioctl.h
cdef extern from "sys/ioctl.h":
  #ioctl has open and close functions aswell as ioctl itself for command parsing#
  int ioctl(int dev, int request, v4l2_ext_controls * argp)
  int open(char *pathname, int flags)
  int close(int fd)

cdef extern from "stdio.h":
  void perror(char *s)

cdef int _opendev(char * devpath):
  #open device with string devpath, it has to be a pointer#
  dev = open(devpath, 0)
  return dev

cdef _closedev(int dev):
  close(dev)

cdef int set_ext_ctrls(int dev, cmds):
  cdef int cmd_count = int(len(cmds))
  cdef v4l2_ext_control xctrls[9]
  cdef v4l2_ext_controls ctrls
  cdef int index = 0
  
  for i in range(cmd_count):
    index = i
    xctrls[index].id = cmds[i]['id'];
    xctrls[index].value = cmds[i]['value'];

  ctrls.count = cmd_count;
  ctrls.controls = xctrls;
  
  cdef int ioctlreturn = -1
  ioctlreturn = ioctl(dev, VIDIOC_S_EXT_CTRLS, &ctrls)
  if (ioctlreturn < 0 ):
    perror("Oops, Extension controls for the driver are probably not inserted. Use libwebcam or guvcview for that")
    
  return ioctlreturn

def opendev(devpath):
  #open device with devpath (python function)#
  VARHOLDER = devpath
  cdef char * devpoint = VARHOLDER
  return _opendev(devpoint)

def closedev(dev):
  _closedev(dev)

def test():
  dev = opendev("/dev/video0")
  reset(dev)
  reset(dev)
  closedev(dev)
  
def reset(int dev):
  set_ext_ctrls(dev, [
      {"id": V4L2_CID_TILT_RESET, "value": 1},
      {"id": V4L2_CID_PAN_RESET, "value": 1}
      ])

def pan(int dev, int steps):
  steps = steps*64
  return set_ext_ctrls(dev, [
      {"id": V4L2_CID_PAN_RELATIVE, "value": steps}
      ])

def pan_abs(int dev, int value):
  return set_ext_ctrls(dev, [
      {"id": V4L2_CID_PAN_ABSOLUTE, "value": value}
      ])

def tilt(int dev, int steps):
  steps = steps*64
  return set_ext_ctrls(dev, [
      {"id": V4L2_CID_TILT_RELATIVE, "value": steps}
      ])

def pantilt(int dev, int pan_steps, int tilt_steps):
  pan_steps = pan_steps*64
  tilt_steps = tilt_steps*64
  return set_ext_ctrls(dev, [
      {"id": V4L2_CID_PAN_RELATIVE, "value": pan_steps},
      {"id": V4L2_CID_TILT_RELATIVE, "value": tilt_steps}
      ])

# Domain: 0 <= value <= 255
def focus(int dev, int value):
  return set_ext_ctrls(dev, [{"id": V4L2_CID_FOCUS_ABSOLUTE, "value": value}])

# def zoom(int dev, int value):
#  return set_ext_ctrls(dev, [{"id": V4L2_CID_ZOOM_ABSOLUTE, "value": value}])

# - 0: Off. The LED is never illuminated, whether or not the device is streaming video.
# - 1: On. The LED is always illuminated, whether or not the device is streaming video.
# - 2: Blinking. The LED blinks, whether or not the device is str# eaming video.
# - 3: Auto. The LED is in control of the device. Typically this means that means that is is illuminated when streaming video and off when not streaming video.
# def led_mode(int dev, int value):
#   return set_ext_ctrls(dev, [{"id": V4L2_CID_LED1_MODE, "value": value}])

# The frequency value only influences the 'Blinking' mode.
# It is expressed in units of 0.05 Hz and sets the blink frequency f.
# The blink interval T = 1/f is defined as the time between two adjoining rising edges (or two adjoining falling edges).
# The following table illustrates the relation between the LED frequency value used in bits 16 to 23, the physical blink frequency, and the physical blink interval.
# +-------------------------------+------------------------+----------------------+
# | Frequency value 20f [0.05 Hz] | Blink frequency f [Hz] | Blink interval T [s] |
# +-------------------------------+------------------------+----------------------+
# | 1                             | 0.05                   | 20                   |
# | 2                             | 0.1                    | 10                   |
# | 10                            | 0.5                    | 2                    |
# | 20                            | 1                      | 1                    |
# | 50                            | 2.5                    | 0.4                  |
# | 100                           | 5                      | 0.2                  |
# +-------------------------------+------------------------+----------------------+
# def led_freq(int dev, int value):
#  return set_ext_ctrls(dev, [{"id": V4L2_CID_LED1_FREQUENCY, "value": value}])


# EXPERIMENTAL

# /usr/include/libv4l2.h
# commandline example: v4l2-ctl --set-ctrl="pan_relative"=200
"""
cdef extern from "libv4l2.h":
  int v4l2_set_control(int fd, int cid, int value)

cdef set_control(int dev, int cid, int value):
  return v4l2_set_control(dev, cid, value)

def v4l2_pan(int dev, int steps):
  return set_control(dev, V4L2_CID_PAN_RELATIVE, steps)
"""
